<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
		<link rel="Stylesheet" type="text/css" href="doc.css" />
		<title>Tutorial: EMF Validation General</title>
	</head>
	<body>
		<h1><a name="top">Tutorial: EMF Validation General</a></h1>

		<h2>Contents</h2>
		<ul>
			<li><a href="#overview">Overview</a></li>
			<li><a href="#refs">References</a></li>
			<li><a href="#intro">Introduction</a></li>
			<li><a href="#construct_batch_constraint">Constructing a Batch Model Constraint</a></li>
			<li><a href="#create_const_provider_extension">Creating the Constraint Provider Extension</a></li>
			<li><a href="#create_client_context">Creating a Client Context</a></li>
			<li><a href="#execute_batch_validate">Executing Batch Validation</a></li>
			<li><a href="#morph_to_live_constraint">Transforming a Batch Constraint into a Live Constraint</a></li>
			<li><a href="#execute_live_validate">Executing Live Validation</a></li>
			<li><a href="#summary">Summary</a></li>
		</ul>

		<h2><a name="overview">Overview</a></h2>
		<p>
			The EMF validation framework provides a means to evaluate and ensure the well-formedness of
			EMF models. Validation comes in two forms: batch and live. While batch validation allows a client to
			explicitly evaluate a group of EObjects and their contents, live validation can be used by clients
			to listen on change notifications to EObjects to immediately verify that the change does not
			violate the well-formedness of the model.
		</p>
		<p>
			Client contexts can be specified to ensure that certain constraints do not get executed outside of
			a certain context. A context is defined by the client to set up their own boundaries from other
			clients.
		</p>
		<p class="small">[<a href="#top">back to top</a>]</p>

		<h2><a name="refs">References</a></h2>
		<p>
			This tutorial assumes that the reader has a knowledge of EMF, and the Eclipse PDE development
			environment. It is essential that the reader understands the basic reflective mechanisms of EMF 
			as well as its adapter/notifier system for broadcasting events.
		</p>
		<p>
			For reference, the full <a href="../references/examples/validationExample.html">example</a> for this tutorial is available.
		</p>
		<p class="small">[<a href="#top">back to top</a>]</p>

		<h2><a name="intro">Introduction</a></h2>
		<p>
			In order to demonstrate EMF Validation, we will be making use of the library metamodel. This metamodel
			is a variant of the standard EMF example metamodel used in many of its tutorials.
		</p>
		<p>
			For those readers who are not familiar with this metamodel, it models a library with books and writers.
			The most important aspect of the library metamodel for this tutorial is the fact that books are modeled
			as EObjects whose EClass is <code>Book</code> and they contain an EStructuralFeature called <code>pages</code>
			that stores an integer number of pages contained in the book.
		</p>
		<p>
			The goal of this tutorial is to create a batch/live EMF validation constraint that will 
			catch cases where there is no unique identifier for the book, library or writer. Also, this tutorial
			will demonstrate how to create a client context allowing a client to run the batch/live constraints
			on a group of EObjects or Notifications.
		</p>
		<p class="small">[<a href="#top">back to top</a>]</p>

		<h2><a name="construct_batch_constraint">Constructing a Batch Model Constraint</a></h2>
		<p>
			A model constraint is written as a subclass of the
			<a href="../references/javadoc/org/eclipse/emf/validation/AbstractModelConstraint.html">AbstractModelConstraint</a>
			that overrides the
			<a href="../references/javadoc/org/eclipse/emf/validation/AbstractModelConstraint.html#validate(org.eclipse.emf.validation.IValidationContext)">validate()</a>
			method. The validate method has the task of taking the input from the validation context and returning either a
			<a href="../references/javadoc/org/eclipse/emf/validation/IValidationContext.html#createSuccessStatus()">ctx.createSuccessStatus()</a>
			or <a href="../references/javadoc/org/eclipse/emf/validation/IValidationContext.html#createFailureStatus(java.lang.Object[])">ctx.createFailureStatus()</a>.
		</p>
		<p>
			Our batch constraint takes the following form:
<pre class="codeblock">
public class NonEmptyNamesConstraint extends AbstractModelConstraint {

	public IStatus validate(IValidationContext ctx) {
		EObject eObj = ctx.getTarget();
		EMFEventType eType = ctx.getEventType();
		
		// In the case of batch mode.
		if (eType == EMFEventType.NULL) {
			String name = null;
			if (eObj instanceof Writer) {
				name = ((Writer)eObj).getName(); 
			} else if (eObj instanceof Library) {
				name = ((Library)eObj).getName();
			} else if (eObj instanceof Book) {
				name = ((Book)eObj).getTitle();
			}
			
			if (name == null || name.length() == 0) {
				return ctx.createFailureStatus(new Object[] {eObj.eClass().getName()});
			}
		}
		
		return ctx.createSuccessStatus();
	}

}
</pre>
		</p>
		<p>
			The target EObject is retrieved from the
			<a href="../references/javadoc/org/eclipse/emf/validation/IValidationContext.html">IValidationContext</a>
			by calling the
			<a href="../references/javadoc/org/eclipse/emf/validation/IValidationContext.html#getTarget()">getTarget()</a>
			method. In order to rule out live validation cases, we check to ensure that the
			<a href="../references/javadoc/org/eclipse/emf/validation/IValidationContext.html#getEventType()">getEventType()</a>
			is <a href="../references/javadoc/org/eclipse/emf/validation/EMFEventType.html#NULL">EMFEventType.NULL</a>.
			If our constraint provider extension is written correctly, we should never be called to perform a live validation.
		</p>
		<p>
			The constraint checks each type of object to ensure that its identifier is not null or empty. In the case
			of a failure, it returns a failure status and places the name of the EObject's EClass to be formatted as
			part of the failure message. Read the following section for more information on the failure message.
		</p>
		<p class="small">[<a href="#top">back to top</a>]</p>

		<h2><a name="create_const_provider_extension">Creating the Constraint Provider Extension</a></h2>
<pre class="codeblock">
   &lt;extension
         point=&quot;org.eclipse.emf.validation.constraintProviders&quot;&gt;
      &lt;category
            name=&quot;Library Constraints&quot;
            id=&quot;org.eclipse.emf.validation.pde.example.general.ui.library&quot;/&gt;
      &lt;constraintProvider cache=&quot;true&quot;&gt;
         &lt;package namespaceUri=&quot;http:///org/eclipse/emf/metamodel/example/pde/library.ecore/1.0.0&quot;/&gt;
         &lt;constraints categories=&quot;org.eclipse.emf.validation.pde.example.general.ui.library&quot;&gt;
            &lt;constraint
                  lang=&quot;Java&quot;
                  class=&quot;org.eclipse.emf.validation.examples.constraints.NonEmptyNamesConstraint&quot;
                  severity=&quot;ERROR&quot;
                  mode=&quot;Batch&quot;
                  name=&quot;Non-Empty Names&quot;
                  id=&quot;org.eclipse.emf.validation.pde.example.general.ui.NameNotEmpty&quot;
                  statusCode=&quot;1&quot;&gt;
               &lt;description&gt;
                  All items in a library model should have some unique identifier or name.
               &lt;/description&gt;
               &lt;message&gt;
                  A {0} has been found to have no unique identifier (name or title).
               &lt;/message&gt;
               &lt;target class=&quot;Library&quot;/&gt;
               &lt;target class=&quot;Writer&quot;/&gt;
               &lt;target class=&quot;Book&quot;/&gt;
               &lt;/target&gt;
            &lt;/constraint&gt;
         &lt;/constraints&gt;
      &lt;/constraintProvider&gt;
   &lt;/extension&gt;
</pre>
		<p>
			The above extension registers a validation category and activates the NonEmptyNamesConstraint in the validation
			service. Categories can be nested and constraints can be placed into one or more of these categories by their
			category identifier. It is worth noting that categories can be defined as mandatory, which means that any
			constraints in that category cannot be enabled/disabled by the client or user. A constraint must only be
			a member of one mandatory category to become mandatory itself even if it is contained in multiple categories.
		</p>
		<p>
			The constraintProvider node refers specifically to the URI of the library EPackage so that references
			in the extension to EClasses and EStructuralFeatures can be properly imported by the service. Finally,
			the constraints node registers our constraint node into the validation service into our category.
		</p>
		<p>
			The constraint node has a number of useful options. For the scope of this tutorial, we will be using
			the &quot;Java&quot; language. By specifying the Java language, we are indicating that the algorithm
			of the constraint will be written in the form of an AbstractModelConstraint class that can be loaded
			in order to perform the validation. The severity of our constraint is an error because it makes it very
			difficult to discern unnamed writers, libraries or books in our editor. We have chosen the batch mode for
			now because we only want users to discover the error if they run validation explicitly. The status code
			was chosen to be a unique number for this plugin.
		</p>
		<p>
			The description and message provide communication to users. The description is used in parts of the user
			interface to list different constraints, provide enablement and to offer a description of the purpose of the
			constraint. The message could be presented to the user to give details of a constraint that failed on a
			particular EObject. The message may contain any number of {0}, {1}, {2} ... substitutions. These substitutions
			are replaced with the objects passed to the <code>ctx.createFailureStatus(new Object[] {...})</code> call 
			in order(see code above).
		</p>
		<p>
			Finally, there are the target nodes. If no target nodes are specified then any EObject of any EClass
			will be given to our validator. In our constraint, we are only interested in Writers, Books and Libraries from
			the library metamodel. These EClasses are qualified by the EPackage URI we provided in the package
			node mentioned above.
		</p>
		<p>
			So far, this would be nearly sufficient to develop a new constraint into an application that
			is already using the validation service and has its own constraints. The only remaining item 
			would be to ensure that this constraint gets bound to the client context of that application. 
			More details on this in the following section.
		</p>
		<p class="small">[<a href="#top">back to top</a>]</p>

		<h2><a name="create_client_context">Creating a Client Context</a></h2>
		<p>
			Client contexts are used by application writers to define the context in which their validation
			will occur. This prevents constraints that were provided by a third-party for a third-party
			application from being executed in the wrong context. In our case, we don't want our constraint
			to be executed in any other context other than our own so we will create our own client context
			and bind our constraint category to our context. The following extension illustrates how this
			is done:
<pre class="codeblock">
   &lt;extension
         point=&quot;org.eclipse.emf.validation.constraintBindings&quot;&gt;
      &lt;clientContext
            default=&quot;false&quot;
            id=&quot;org.eclipse.emf.validation.pde.example.general.ui.libraryContext&quot;&gt;
         &lt;selector class=&quot;org.eclipse.emf.validation.examples.constraints.ValidationDelegateClientSelector&quot;/&gt;
      &lt;/clientContext&gt;
      &lt;binding
            context=&quot;org.eclipse.emf.validation.pde.example.general.ui.libraryContext&quot;
            category=&quot;org.eclipse.emf.validation.pde.example.general.ui.library&quot;/&gt;
   &lt;/extension&gt; 
</pre>
		</p>
		<p>
			This extension registers the client context that is not a &quot;default&quot; context. Default contexts
			will accumulate constraints and categories that have not been bound to any context. We provide a unique
			identifier and a selector class for this context. The selector has the purpose of discovering whether
			an EObject belongs to the context. A context binding is set up to link our category with our client
			context. The selector is a simple static latch that we will latch whenever we call the validation service
			in the next section:
<pre class="codeblock">
// NOTE: This is _NOT_ a recommended approach to writing a client selector.
//       Suggested approaches:
//           -Check the resource of the EObject either by identity or by URI
//            as long as this resource is somehow unique to this application
//           -Check the identity of the resource set to ensure that it is some
//            private object
//           -Check the identity of the EObject itself to see if it belongs to
//            some private collection
//           -Check the EClass of the EObject but only if the metamodel is private
//            to this application and will not be used by other contexts
public class ValidationDelegateClientSelector implements IClientSelector {

	public static boolean running = false;
	
	public boolean selects(Object object) {
		return running;
	}
}
</pre>
		</p>
		<p>
			Using a client selector is not the only approach that can be used to categorize an EObject as part
			of a client context. An alternative would be to use an XML enablement expression in an enablement node
			of the clientContext node in the constraint bindings extension. These expressions can be constructed 
			in the XML to reflectively produce a true/false value when evaluated against a Java object. 
			See the
			<a href="/help/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/expressions/package-summary.html">org.eclipse.core.expressions</a>
			package for more details.
		</p>
		<p class="small">[<a href="#top">back to top</a>]</p>

		<h2><a name="execute_batch_validate">Executing Batch Validation</a></h2>
		<p>
			Now that the constraint has been registered and the category has been bound to our client context we
			can call the validation service to perform a batch validation like this:
<pre class="codeblock">
ValidationDelegateClientSelector.running = true;

IBatchValidator validator = (IBatchValidator)ModelValidationService.getInstance()
	.newValidator(EvaluationMode.BATCH);
validator.setIncludeLiveConstraints(true);

IStatus status = validator.validate(selectedEObjects);
ValidationDelegateClientSelector.running = false;
</pre>
		</p>
		<p>
			The first part of this code snippet enables the latch so that the validation service will determine
			that the provided EObjects belong to our client context. We requested a batch validation and asked
			that the batch validator include live validation constraints because live validation constraints
			are often written to handle the batch validation case. Finally, we validate the selected EObjects
			and are given back the status of the validation. This status obeys the regular <code>IStatus</code>
			rules and may be a composite or a non-composite status object. The status may have an ERROR/WARNING/OK
			code, which indicates the worst status code of all of the statuses given back by the evaluated
			constraints. In order to prevent our client context from interfering with other client contexts,
			we release the client selector latch. Once the batch validator has been constructed, it can be reused
			to perform validation at a later time.
		</p>
		<p class="small">[<a href="#top">back to top</a>]</p>

		<h2><a name="morph_to_live_constraint">Transforming a Batch Constraint into a Live Constraint</a></h2>
		<p>
			Our constraint can be modified to be a live constraint so it can be used by the validation service
			to validate notifications coming from notifiers of an EMF model. Within the notification, information
			such as the modified structural feature, the old value and the new value is available to our constraint.
			Also, our extension may specify the exact structural features that we are interested in validating.
			Here is the modified constraint class and extension:
<pre class="codeblock">
public class NonEmptyNamesConstraint
	extends AbstractModelConstraint {

	public IStatus validate(IValidationContext ctx) {
		EObject eObj = ctx.getTarget();
		EMFEventType eType = ctx.getEventType();
		
		// In the case of batch mode.
		if (eType == EMFEventType.NULL) {
			String name = null;
			if (eObj instanceof Writer) {
				name = ((Writer)eObj).getName(); 
			} else if (eObj instanceof Library) {
				name = ((Library)eObj).getName();
			} else if (eObj instanceof Book) {
				name = ((Book)eObj).getTitle();
			}
			
			if (name == null || name.length() == 0) {
				return ctx.createFailureStatus(new Object[] {eObj.eClass().getName()});
			}
		// In the case of live mode.
		} else {
			Object newValue = ctx.getFeatureNewValue();
			
			if (newValue == null || ((String)newValue).length() == 0) {
				return ctx.createFailureStatus(new Object[] {eObj.eClass().getName()});
			}
		}
		
		return ctx.createSuccessStatus();
	}

}
</pre>
		</p>
		<p>
			The changes to the class include a new case where it is invoked in live validation mode. In this case,
			the exact structural feature does not need to be checked because the extension below will register the constraint
			against only one specific identification feature for each EClass. Finally, it checks the new value
			of the identification feature to ensure that it is not null nor empty.
		</p>
<pre class="codeblock">
   &lt;extension
         point=&quot;org.eclipse.emf.validation.constraintProviders&quot;&gt;
      &lt;category
            name=&quot;Library Constraints&quot;
            id=&quot;org.eclipse.emf.validation.pde.example.general.ui.library&quot;/&gt;
      &lt;constraintProvider cache=&quot;true&quot;&gt;
         &lt;package namespaceUri=&quot;http:///org/eclipse/emf/metamodel/example/pde/library.ecore&quot;/&gt;
         &lt;constraints categories=&quot;org.eclipse.emf.validation.pde.example.general.ui.library&quot;&gt;
            &lt;constraint
                  lang=&quot;Java&quot;
                  class=&quot;org.eclipse.emf.validation.examples.constraints.NonEmptyNamesConstraint&quot;
                  severity=&quot;ERROR&quot;
                  mode=&quot;Live&quot;
                  name=&quot;Non-Empty Names&quot;
                  id=&quot;org.eclipse.emf.validation.pde.example.general.ui.NameNotEmpty&quot;
                  statusCode=&quot;1&quot;&gt;
               &lt;description&gt;
                  All items in a library model should have some unique identifier or name.
               &lt;/description&gt;
               &lt;message&gt;
                  A {0} has been found to have no unique identifier (name or title).
               &lt;/message&gt;
               &lt;target class=&quot;Library&quot;&gt;
                  &lt;event name=&quot;Set&quot;&gt;
                     &lt;feature name=&quot;name&quot;/&gt;
                  &lt;/event&gt;
                  &lt;event name=&quot;Unset&quot;&gt;
                     &lt;feature name=&quot;name&quot;/&gt;
                  &lt;/event&gt;
               &lt;/target&gt;
               &lt;target class=&quot;Writer&quot;&gt;
                  &lt;event name=&quot;Set&quot;&gt;
                     &lt;feature name=&quot;name&quot;/&gt;
                  &lt;/event&gt;
                  &lt;event name=&quot;Unset&quot;&gt;
                     &lt;feature name=&quot;name&quot;/&gt;
                  &lt;/event&gt;
               &lt;/target&gt;
               &lt;target class=&quot;Book&quot;&gt;
                  &lt;event name=&quot;Set&quot;&gt;
                     &lt;feature name=&quot;title&quot;/&gt;
                  &lt;/event&gt;
                  &lt;event name=&quot;Unset&quot;&gt;
                     &lt;feature name=&quot;title&quot;/&gt;
                  &lt;/event&gt;
               &lt;/target&gt;
            &lt;/constraint&gt;
         &lt;/constraints&gt;
      &lt;/constraintProvider&gt;
   &lt;/extension&gt;
</pre>
		<p>
			The extension has changed in a few key places. We have modified its mode to be &quot;Live.&quot; This
			constraint will still get called by the validation service for batch validation because we called
			<a href="../references/javadoc/org/eclipse/emf/validation/service/IBatchValidator.html#setIncludeLiveConstraints(boolean)">validator.setIncludeLiveConstraints(true)</a>
			when we perform batch validation in the case above (see Executing Batch Validation). We have augmented
			each of the target nodes to include specific notification events and structural features for each
			EClass. The validation service will only call our constraint if the notification matches the EClass,
			EStructuralFeature and event type we have specified.
		</p>
		<p class="small">[<a href="#top">back to top</a>]</p>

		<h2><a name="execute_live_validate">Executing Live Validation</a></h2>
		<p>
			Live validation is not called in the typical way that batch validation is called. We will be attaching
			an adapter to a group of notifiers in order to get notifications when those notifiers are changed. If the
			adapter is attached as a content adapter to a resource, then notifications will be given for all EObjects
			contained in that EObject:
<pre class="codeblock">
Resource r = (Resource)i.next();

if (!resourceHasAdapter(r)) {
	EContentAdapter liveValidationContentAdapter = new LiveValidationContentAdapter();
	r.eAdapters().add(liveValidationContentAdapter);
}
</pre>
<p>
The content adapter will have to modify the client context latch as we did in the batch validation.
This will guarantee that our notifier EObjects will be included in our client context, which will
allow the validation service to call our constraint:
</p>
<pre class="codeblock">
class LiveValidationContentAdapter extends EContentAdapter {
	private ILiveValidator validator = null;

	LiveValidationContentAdapter() {
	}

	public void notifyChanged(final Notification notification) {
		super.notifyChanged(notification);
		
		if (validator == null) {
			ILiveValidator validator = 
				(ILiveValidator)ModelValidationService.getInstance().newValidator(EvaluationMode.LIVE);
			
		}
		
		ValidationDelegateClientSelector.running = true;
		
		IStatus status = validator.validate(notification);
		
		if (!status.isOK()) {
			if (status.isMultiStatus()) {
				status = status.getChildren()[0];
			}
			
			System.out.println("The current modification has violated one or more live constraints");
		}
		
		ValidationDelegateClientSelector.running = false;
	}
}
</pre>
		</p>
		<p>
			As in the case of the batch validation, the details of the validation failures/successes can be
			retrieved through the returned IStatus object.
		</p>
		<p class="small">[<a href="#top">back to top</a>]</p>

		<h2><a name="summary">Summary</a></h2>
		<p>
			In this tutorial, we did the following:
			<ol>
				<li>Developed a batch validation constraint.</li>
				<li>Created the constraint provider extension.</li>
				<li>Created a client context for use in our application.</li>
				<li>Ran validation against a collection of EObjects in batch mode.</li>
				<li>Transformed the batch validation constraint into a dual mode live/batch validation constraint.</li>
				<li>Modified the constraint provider extension appropriately.</li>
				<li>Developed a content adapter to provide live validation for a particular EMF resource.</li>
			</ol>
		</p>
		<p class="small">[<a href="#top">back to top</a>]</p>

		<hr />

		<p>
			<a href="https://www.eclipse.org/legal/epl-2.0/">Copyright (c) 2000, 2007 IBM Corporation and others.</a>
		</p>
	</body>
</html>
